﻿using System;
using System.Collections.Generic;

namespace DigitalQuran.Collection
{
    /// <summary>
    /// Collection of <see cref="DigitalQuran.Verse"/>
    /// </summary>
    public class VerseCollection : ReadOnlyCollection<Verse>
    {
        /// <summary>
        /// Total verses in Qur'an
        /// </summary>
        public const int TotalVerses = 6236;

        internal VerseCollection() : this(0, TotalVerses) { }

        int startIndex = 0;

        /// <summary>
        /// Creates new subset of <see cref="DigitalQuran.Collection.VerseCollection"/>
        /// </summary>
        /// <param name="startIndex">Zero based index of First Verse in collection</param>
        /// <param name="count">Total number of verses to include in collection</param>
        public VerseCollection(int startIndex, int count)
            : base(count)
        {
            this.startIndex = startIndex;
        }

        public override Verse this[int index]
        {
            get
            {
                if (index < Count)
                    return _Verses[index + startIndex];
                else
                    throw new IndexOutOfRangeException();
            }
        }

        public override IEnumerator<Verse> GetEnumerator()
        {
            for (int i = 0; i < Count; i++)
            {
                yield return _Verses[i + startIndex];
            }
        }

        int? _WordCount = null;
        /// <summary>
        /// Gets Total Numbers of Word by all the Verses of this Instance
        /// </summary>
        public int WordCount
        {
            get
            {
                if (!_WordCount.HasValue)
                {
                    _WordCount = 0;
                    foreach (var verse in this)
                        _WordCount += verse.Words.Count;
                }

                return _WordCount.Value;
            }
        }

        int? _LetterCount = null;
        /// <summary>
        /// Gets Total Numbers of Letters by all the Verses of this Instance
        /// </summary>
        public int LetterCount
        {
            get
            {
                if (!_LetterCount.HasValue)
                {
                    _LetterCount = 0;
                    foreach (var verse in this)
                        _LetterCount += verse.Words.LetterCount;
                }

                return _LetterCount.Value;
            }
        }

        List<Letter> _UniqueLetters = null;
        /// <summary>
        /// Gets Collection of Unique Letters
        /// </summary>
        public List<Letter> UniqueLetters
        {
            get
            {
                if (_UniqueLetters == null)
                {
                    _UniqueLetters = new List<Letter>();
                    foreach (var verse in this)
                        foreach (var word in verse.Words)
                            foreach (var letter in word.Letters)
                                if (!_UniqueLetters.Contains(letter))
                                {
                                    _UniqueLetters.Add(letter);
                                }
                }

                return _UniqueLetters;
            }
        }

        /// <summary>
        /// Returns Frequency of Letter
        /// </summary>
        /// <param name="character"></param>
        /// <returns></returns>
        public int GetLetterFrequency(char character)
        {
            int result = 0;
            foreach (Verse verse in this)
                result += verse.Words.GetLetterFrequency(character);

            return result;
        }

        /// <summary>
        /// Gets the specific word in this verse
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public Word GetWord(int index)
        {
            return WordCollection.GetWord(this[0].Words[0].GlobalNumber - 1 + index);
        }

        static Verse[] _Verses = new Verse[TotalVerses];
        internal static void LoadData(IEnumerator<string[]> e)
        {
            int wId = 0;
            for (int i = 0; i < TotalVerses; i++)
            {
                e.MoveNext();
                _Verses[i] = new Verse(i, wId, e.Current);

                wId += _Verses[i].Words.Count;
            }
        }

        /// <summary>
        /// Get the verse at specified index
        /// </summary>
        /// <param name="index">Index of Verse</param>
        /// <returns>Returns <see cref="DigitalQuran.Verse"/></returns>
        public static Verse GetVerse(int index)
        {
            return _Verses[index];
        }

        internal static void UpdateText(string textMode)
        {
            foreach (var verse in _Verses)
            {
                verse.ActiveText = verse.Words.ToString(textMode);
            }
        }

        public static void UpdateValues(Numerology.NumerologyEngine systems) {
            foreach (var verse in _Verses) {
                systems.CalculateValue(verse);
            }
        }
    }

    /// <summary>
    /// Extended Collection of <see cref="DigitalQuran.Verse"/>
    /// </summary>
    public class VerseCollectionEx : VerseCollection {

        /// <summary>
        /// Create new Instance
        /// </summary>
        /// <param name="indexes">List of Verse Indexes to include in collection</param>
        public VerseCollectionEx(List<int> indexes)
            : base(0, VerseCollection.TotalVerses) {
            this.indexes = indexes;
        }

        List<int> indexes;

        public override Verse this[int index] {
            get {
                return base[indexes[index]];
            }
        }

        public override IEnumerator<Verse> GetEnumerator() {
            foreach (var index in indexes) {
                yield return base[index];
            }
        }
    }
}